#include "stdafx.h"

int DLinkedList_IsEmpty(PDLINKEDLIST list) {
	return (list->head == NULL && list->tail == NULL);
}

int DLinkedList_IsHead(PDLINKEDLIST list,
					   PDECIMALNODE node) {
	return (node == list->head && node != NULL);
}

int DLinkedList_IsTail(PDLINKEDLIST list,
					   PDECIMALNODE node) {
	return (node == list->tail && node != NULL);
}

PDLINKEDLIST DLinkedList_CreateList() {
	PDLINKEDLIST list = NULL;
	list = (PDLINKEDLIST)malloc(sizeof(DLINKEDLIST));
	list->head = list->tail = NULL;
	return list;
}

void DLinkedList_ReleaseList(PDLINKEDLIST list) {
	PDECIMALNODE node = NULL;
	PDECIMALNODE node_next = NULL;

	node = list->head;
	while (node != NULL) {
		node_next = node->next;
		DLinkedList_ReleaseNode(node);
		node = node->next;
	}
}

PDECIMALNODE DLinkedList_CreateNode(unsigned char value) {
	PDECIMALNODE node = NULL;
	node = (PDECIMALNODE)malloc(sizeof(DECIMALNODE));
	node->next = node->prev = NULL;
	node->value = value;
	return node;
}

PDECIMALNODE DLinkedList_AppendNode(PDLINKEDLIST list,
									PDECIMALNODE node) {
	if (DLinkedList_IsEmpty(list)) {
		node->prev = node->next = NULL;
		list->head = list->tail = node;
	} else {		
		node->prev = list->tail;
		node->next = NULL;
		list->tail->next = node;
		list->tail = node;
	}
	return node;
}

PDECIMALNODE DLinkedList_RemoveNodeFromTail(PDLINKEDLIST list) {
	PDECIMALNODE node = NULL;
	if (!DLinkedList_IsEmpty(list)) {
		node = list->tail;
		if (list->head == list->tail) {
			list->head = list->tail = NULL;
		} else {
			list->tail = node->prev;
			list->tail->next = NULL;
		}
	}
	return node;
}

PDECIMALNODE DLinkedList_RemoveNodeFromHead(PDLINKEDLIST list) {
	PDECIMALNODE node = NULL;
	if (!DLinkedList_IsEmpty(list)) {
		node = list->head;
		if (list->head == list->tail) {
			list->head = list->tail = NULL;
		} else {
			list->head = node->next;
			list->head->prev = NULL;
		}
	}
	return node;
}

void DLinkedList_ReleaseNode(PDECIMALNODE node) {
	if (node) free(node);
}

PBIGDECIMAL BigDecimal_CreateBigDecimal() {
	PBIGDECIMAL decimal = NULL;
	decimal = (PBIGDECIMAL)malloc(sizeof(BIGDECIMAL));
	decimal->posi = 1;
	decimal->inte = DLinkedList_CreateList();
	decimal->floa = DLinkedList_CreateList();
	return decimal;
}

void BigDecimal_ReleaseBigDecimal(PBIGDECIMAL decimal) {
	DLinkedList_ReleaseList(decimal->floa);
	DLinkedList_ReleaseList(decimal->inte);
}

void BigDecimal_OutputBigDecimal(PBIGDECIMAL decimal) {
	PDLINKEDLIST list = NULL;
	PDECIMALNODE node = NULL;

	printf("[output - big decimal] : ");

	if (decimal) {
		list = decimal->inte;
		node = list->tail;
		if (!DLinkedList_IsEmpty(list)) {
			while (node != NULL) {
				printf("%d",node->value);
				node = node->prev;
			}
		} else {
			printf("0");
		}

		printf(".");

		list = decimal->floa;
		node = list->head;
		if (!DLinkedList_IsEmpty(list)) {
			while (node != NULL) {
				printf("%d",node->value);
				node = node->next;
			}
		}

		printf("\n");
	} else {
		printf("nothing\n");
	}
}

PBIGDECIMAL BigDecimal_ConvertFromString(const char * str,
										 int len) {
	char c = 0;
	int m = 0;
	PBIGDECIMAL decimal = NULL;

	if (str == NULL || len <= 0) return decimal;

	decimal = BigDecimal_CreateBigDecimal();

	if (decimal == NULL) return NULL;

	c = str[0];
	if (c == '-') {
		decimal->posi = 1;
	} else {
		for (int i = 0; i < len; i++) {

		}	
	}
}

PBIGDECIMAL BigDecimal_Plus(PBIGDECIMAL decimal0,
							PBIGDECIMAL decimal1) {
	unsigned char forward = 0;

	unsigned char value = 0;
	unsigned char value0 = 0;
	unsigned char value1 = 0;
	
	PBIGDECIMAL decimal = NULL;
	
	PDLINKEDLIST list = NULL;
	PDLINKEDLIST list0 = NULL;
	PDLINKEDLIST list1 = NULL;

	PDECIMALNODE node = NULL;
	PDECIMALNODE node0 = NULL;
	PDECIMALNODE node1 = NULL;
	PDECIMALNODE tem = NULL;

	decimal = BigDecimal_CreateBigDecimal();

	/* float */

	list = decimal->floa;
	list0 = decimal0->floa;
	list1 = decimal1->floa;
	
	node0 = list0->head;
	node1 = list1->head;

	while (node0 != NULL || node1 != NULL) {
		value0 = node0 == NULL ? 0 : node0->value;
		value1 = node1 == NULL ? 0 : node1->value;
		
		value = value0 + value1;
		
		forward = value >= 10 ? 1 : 0;
		
		node = DLinkedList_CreateNode(value%10);
		
		DLinkedList_AppendNode(list,node);
		
		tem = node;

		while (forward && !DLinkedList_IsHead(list,tem)) {
			tem->value += forward;
			if (tem->value >= 10) {
				forward = 1;
				tem->value -= 10;
				tem = tem->prev;
			} else forward = 0;
		}

		if (node0 != NULL) node0 = node0->next;
		if (node1 != NULL) node1 = node1->next;
	}

	node = list->head;

	forward = node->value >= 10 ? 1 : 0;

	/* integer */

	list = decimal->inte;
	list0 = decimal0->inte;
	list1 = decimal1->inte;

	node0 = list0->head;
	node1 = list1->head;

	while (node0 != NULL || node1 != NULL) {
		value0 = node0 == NULL ? 0 : node0->value;
		value1 = node1 == NULL ? 0 : node1->value;

		value = value0 + value1 + forward;

		node = DLinkedList_CreateNode(value%10);

		DLinkedList_AppendNode(list,node);

		forward = value >= 10 ? 1 : 0;

		if (node0 != NULL) node0 = node0->next;
		if (node1 != NULL) node1 = node1->next;
	}
}

PBIGDECIMAL BigDecimal_Minu(PBIGDECIMAL decimal0,
							PBIGDECIMAL decimal1) {
	return NULL;
}

PBIGDECIMAL BigDecimal_Mult(PBIGDECIMAL decimal0,
							PBIGDECIMAL decimal1) {
	return NULL;
}

PBIGDECIMAL BigDecimal_Divi(PBIGDECIMAL decimal0,
							PBIGDECIMAL decimal1) {
	return NULL;
}

PBIGDECIMAL BigDecimal_Fact(PBIGDECIMAL decimal) {
	return NULL;
}